package com.shangxia.dreaming.business;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.shangxia.dreaming.business.pojo.AgeCount;
import com.shangxia.dreaming.business.pojo.TempData;
import com.shangxia.dreaming.common.content.FileContentEnum;
import com.shangxia.dreaming.common.util.excelUtil.HeadFactory;
import com.shangxia.dreaming.common.util.excelUtil.ReadExcelUtil;
import com.shangxia.dreaming.common.util.excelUtil.WriteHandler.MyEasyWriteHandler;
import com.shangxia.dreaming.common.util.excelUtil.WriteHandler.MyPurpleAllWriteHandler;
import com.shangxia.dreaming.common.util.excelUtil.WriteHandler.MyPurpleAllWriteHandler2;
import com.shangxia.dreaming.common.util.excelUtil.listener.NoModelDataListener;
import com.shangxia.dreaming.common.util.txtUtil.ReadTXT;
import com.shangxia.dreaming.common.util.txtUtil.WriteTXT;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

import static com.shangxia.dreaming.common.content.ConditionContent.*;
import static com.shangxia.dreaming.common.content.ConditionContent.MIN_COUNT_AGE;
import static com.shangxia.dreaming.common.util.txtUtil.ReadTXT.*;
import static java.util.Comparator.comparingInt;

/**
 * @ProjectName: dreaming
 * @ClassName: SecondJob
 * @Time: 2020/10/10
 * @Author: zhouy
 * @Description:
 * @Experience:
 */

@Slf4j
@Component
public class SecondJob {
    @Resource
    private PrePareJob prePareJob = new PrePareJob();

    public void work() throws IOException, CloneNotSupportedException {

        //读取真号
        List<List<Integer>> realCodeLists = ReadTXT.readList_List_int();

        //翻表
        List<Integer>[][] arr = prePareJob.turnTable(realCodeLists, realCodeLists.size(), SON_CODE_LENGTH, SUM_CODE_LENGTH);
        //输出主要结果
        List<List<String>> resultLists = new ArrayList<>();
        //第二次统计结果

        //读取历史结果
        readResultLists(resultLists);
        //删除最后一期预测结果
        if (resultLists.size() > 2) {
            resultLists.remove(resultLists.size() - 1);
        }
        //第三步 初始化统计map 每层的位置TempData的list
        Map<Integer, List<TempData>> indexMapListMap = new HashMap<>();

        Map<String, TempData> continueDataMaps = new HashMap<>();

        //中奖的数据
        List<TempData> dataTrues = readTempDataList("dataTrues");
        Map<Integer, List<TempData>> tempDataTruesMap = readMap_int_TempDataList("tempDataTruesMap");
        Set<String> trueIndexCol = new HashSet<>(readStrList("trueIndexCol"));
        //移除的
        List<TempData> continueRemoveDataMaps = new ArrayList<>();
        //最大翻表层数
        int limit = Math.min(realCodeLists.size(), MUST_TURN_TABLE_COLUMN);
        //开始计算期数
        int row = 0;
        int maxSize = NoModelDataListener.MAXSIZE;

        //初始 化初始化统计map 每层的位置TempData的list
        if (resultLists.size() > 0) {
            indexMapListMap = readMap_int_TempDataList("indexMapListMap");
            row = readRow("row") + 1;
        }
        int startNum = indexMapListMap.size();
        for (int i = startNum; i < limit; i++) {
            List<TempData> indexMapList = new ArrayList<>();
            initIndexMapList(indexMapList, SUM_CODE_LENGTH + 1, SON_CHECK_CODE_LENGTH, i);
            indexMapListMap.put(i, indexMapList);
        }

        for (; row < realCodeLists.size(); row++) {
            if (row == realCodeLists.size() - 1) {
                break;
            }
            if (row % 100 == 0) {
                log.info("计算第" + row + "期");
            }
            List<TempData> celDataMapList = new ArrayList<>();
            for (int col = 0; col < limit; col++) {

                if (row < col) {
                    continue;
                }
                List<TempData> indexMapList = indexMapListMap.get(col);
                //5个真号
                List<Integer> realList = arr[row + 1][col].subList(SUM_CODE_LENGTH - SON_CODE_LENGTH, SUM_CODE_LENGTH);
                //5个真号对应位置
                List<Integer> realIndexList = new ArrayList<>();
                for (Integer realInt : realList) {
                    realIndexList.add(arr[row][col].indexOf(realInt) + 1);
                }
                //5个真号对应位置组成的红3号
                realIndexList.sort(comparingInt(o -> o));
//                List<String> sonListStr = getSonListStr(realIndexList, SON_CHECK_CODE_LENGTH);
                //红3号计数
                updateIndexMap(indexMapList, realIndexList, continueDataMaps, row, arr[row], col, trueIndexCol, dataTrues,
                        tempDataTruesMap, continueRemoveDataMaps);
                List<TempData> collect = indexMapList.stream().filter(dataMap -> dataMap.getCount() > MIN_COUNT_AGE).collect(Collectors.toList());

                try {
                    for (TempData dataMap : collect) {
                        setRealFirstCode(arr[row], col, dataMap);
                        if (dataMap.getFlag()) {
                            trueIndexCol.add(dataMap.getIndex() + "=" + dataMap.getCol());
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
                celDataMapList.addAll(collect);
            }
            if (celDataMapList.size() == 0) {
                continue;
            }
            maxSize = Math.max(maxSize, celDataMapList.size());
            celDataMapList.sort((o1, o2) -> o2.getCount() - o1.getCount());
            List<String> result = new ArrayList<>(celDataMapList.size() * 5);
            result.add(row + 1 + "");
            for (TempData tempData : celDataMapList) {
                result.add(tempData.getIndex());
                result.add(tempData.getCount() + "");
                result.add(tempData.getRealFirstCode());
                result.add(tempData.getCol() + 1 + "");
                result.add("" + tempData.getFlag());
            }
            if (result.size() > 10000) {
                log.error("数据量太大，无法打印。请增加最小年龄限制");
            }
            resultLists.add(result);
            if (row == realCodeLists.size() - 2) {
                //save中间结果
                WriteTXT.saveStr("row", row);
                WriteTXT.saveMap_int_List(indexMapListMap, "indexMapListMap");
            }
        }

        WriteTXT.saveStrList(new ArrayList<>(trueIndexCol), "trueIndexCol");

        //预测下期号码
        List<String> realLastList = getLastGuessCode(arr, row, resultLists);
        resultLists.add(realLastList);
        log.info("结果数=" + realLastList.size());
        //输出结果：超过结果
        saveResult(resultLists, maxSize, "超过结果");
//        saveCountTrueLength(resultLists, maxSize, "相邻true年龄");
        WriteTXT.saveTempDataList(dataTrues, "dataTrues");
        //输出结果：第二次超过结果
        exportTrueMap(arr, row, tempDataTruesMap);
        //输出结果：年龄统计结果
        exportCountAge2(resultLists, tempDataTruesMap.values());
    }

    private void saveCountTrueLength(List<List<String>> resultLists, Integer maxSize, String fileName) throws IOException {
        List<Integer> list = new ArrayList<>(maxSize);
        for (Integer integer = 0; integer < maxSize; integer++) {
            list.add(0);
        }
        Map<Integer, Map<String, String>> mapMap = new HashMap<>();
        for (List<String> resultList : resultLists) {
            for (int i = 0; i < resultList.size() - 5; i = i + 5) {
                if ("true".equals(resultList.get(i + 5))) {
                    Map<String, String> map;
                    if (mapMap.containsKey(i / 5)) {
                        map = mapMap.get(i / 5);
                        if (list.size() > i / 5) {
                            Integer remove = list.remove(i / 5);
                            list.add(i / 5, Math.max(remove, Integer.parseInt(resultList.get(0)) - Integer.parseInt(map.get("status"))));
                        } else {
                            list.add(i / 5, Integer.parseInt(resultList.get(0)) - Integer.parseInt(map.get("status")));
                        }
                    } else {
                        map = new HashMap<>();
                        map.put("status", resultList.get(0));
                        mapMap.put(i / 5, map);
                    }

                }
            }
        }
        WriteTXT.saveIntList(list, fileName);
    }

    private void updateIndexMap(List<TempData> indexMapList, List<Integer> realIndexList) {
        for (TempData tempData : indexMapList) {
            List<String> list1 = new ArrayList<>(Arrays.asList(tempData.getIndex().split(",")));
            List<String> list2 = new ArrayList<>();
            for (Integer integer : realIndexList) {
                list2.add(integer + "");
            }
            if (list1.containsAll(list2)) {
                tempData.setCount(0);
            } else {
                tempData.setCount(tempData.getCount() + 1);
            }
        }
    }

    private void saveResult(List<List<String>> resultLists, int maxSize, String fileName) {
        File file = new File(PATH_Result + fileName + FileContentEnum.EXCEL_END);
        if (file.exists()) {
            file.delete();
        }
        EasyExcel.write(file).head(HeadFactory.head1(maxSize)).sheet("超过结果").registerWriteHandler(new MyPurpleAllWriteHandler()).doWrite(resultLists);
    }

    private void initIndexMapList(List<TempData> indexMapList, int sum, int son, int col) {
        for (int i = 1; i < sum; i++) {
            for (int j = i + 1; j < sum; j++) {
                if (son == 2) {
                    indexMapList.add(new TempData(i + "," + j, 1, col));
                } else {
                    for (int k = j + 1; k < sum; k++) {
                        if (son == 3) {
                            indexMapList.add(new TempData(i + "," + j + "," + k, 1, col));
                        } else {
                            for (int m = k + 1; m < sum; m++) {
                                indexMapList.add(new TempData(i + "," + j + "," + k + "," + m, 1, col));
                            }
                        }
                    }
                }
            }
        }
    }

    private void exportTrueMap(List<Integer>[][] arr, int row, Map<Integer, List<TempData>> Map) throws IOException {
        WriteTXT.saveMap_int_List(Map, "tempDataTruesMap");
        List<List<String>> lists = new ArrayList<>();
        int maxCount = 0;//最长小列数
        for (java.util.Map.Entry<Integer, List<TempData>> entry : Map.entrySet()) {
            List<String> list = new ArrayList<>();
            list.add(entry.getKey() + "");
            List<TempData> values = entry.getValue();
            values.sort((o1, o2) -> o2.getCount() - o1.getCount());
            for (TempData value : values) {
                list.add(value.getIndex());
                list.add(value.getCount() + "");
                list.add(value.getRealFirstCode());
                list.add(1 + value.getCol() + "");
                list.add(value.getFlag() + "");
            }
            lists.add(list);
            maxCount = Math.max(maxCount, list.size());
        }
        File file = new File(PATH_Result + "第二次超过结果.xlsx");
        if (file.exists()) {
            file.delete();
        }
        List<List<String>> sedResultLists = new ArrayList<>();

        sedResultLists.addAll(lists);
        sedResultLists.sort(comparingInt(list -> Integer.parseInt(list.get(0))));
        List<String> realLastList = getLastGuessCode(arr, row, sedResultLists);
        sedResultLists.add(realLastList);

        EasyExcel.write(file).head(HeadFactory.head1(maxCount / 5)).sheet("第二次超过结果").registerWriteHandler(new MyPurpleAllWriteHandler2()).doWrite(sedResultLists);
    }

    private void exportCountAge2(List<List<String>> resultLists, Collection<List<TempData>> values) {
        Map<String, AgeCount> ageCountMap = new LinkedHashMap<>();
        for (List<String> resultList : resultLists) {
            for (int i = 5; i < resultList.size(); i = i + 5) {
                if ("true".equals(resultList.get(i))) {
                    if (ageCountMap.containsKey(resultList.get(i - 3))) {
                        AgeCount ageCount = ageCountMap.get(resultList.get(i - 3));
                        ageCount.setCount(ageCount.getCount() + 1);
                        ageCount.setState(ageCount.getState() + "," + resultList.get(0));
                        ageCountMap.put(resultList.get(i - 3), ageCount);
                    } else {
                        AgeCount ageCount = new AgeCount();
                        ageCount.setAge(Integer.parseInt(resultList.get(i - 3)));
                        ageCount.setCount(1);
                        ageCount.setState(resultList.get(0));
                        ageCountMap.put(resultList.get(i - 3), ageCount);
                    }
                }
            }
        }
        List<String> list = new ArrayList<>(ageCountMap.keySet());
        list.sort((o1, o2) -> Integer.parseInt(o2) - Integer.parseInt(o1));
        List<List<String>> lists1 = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            List<String> resultList = new ArrayList<>();
            AgeCount ageCount = ageCountMap.get(list.get(i));
            resultList.add(ageCount.getAge() + "");
            resultList.add(ageCount.getCount() + "");
            resultList.add(ageCount.getState());
            lists1.add(resultList);
        }
        Map<Integer, List<TempData>> map = new HashMap<>();
        for (List<TempData> listD : values) {
            for (TempData dataMap : listD) {
                if (dataMap.getFlag()) {
                    if (map.containsKey(dataMap.getCount())) {
                        map.get(dataMap.getCount()).add(dataMap);
                    } else {
                        List<TempData> list1 = new ArrayList<>();
                        list1.add(dataMap);
                        map.put(dataMap.getCount(), list1);
                    }
                }
            }
        }
        List<List<String>> lists2 = new ArrayList<>();
        for (Map.Entry<Integer, List<TempData>> entry : map.entrySet()) {
            List<String> list0 = new ArrayList<>();
            list0.add(entry.getKey() + "");
            list0.add(entry.getValue().size() + "");
            StringBuffer sb = new StringBuffer();
            for (TempData dataMap : entry.getValue()) {
                sb.append(dataMap.getWinRow() + ",");
            }
            list0.add(sb.toString());
            lists2.add(list0);
        }
        lists2.sort((o1, o2) -> Integer.parseInt(o2.get(0)) - Integer.parseInt(o1.get(0)));
        File file2 = new File(PATH_Result + "年龄统计结果.xlsx");
        if (file2.exists()) {
            file2.delete();
        }
        ExcelWriter excelWriter = EasyExcel.write(file2).registerWriteHandler(new MyEasyWriteHandler()).head(HeadFactory.head2()).build();
        WriteSheet writeSheet0 = EasyExcel.writerSheet(0, "年龄统计结果").build();
        WriteSheet writeSheet1 = EasyExcel.writerSheet(1, "第二次年龄统计结果").build();
        excelWriter.write(lists1, writeSheet0);
        excelWriter.write(lists2, writeSheet1);
        if (excelWriter != null) {
            excelWriter.finish();
        }

    }


    public List<String> getSonListStr(List<Integer> list, int son) {
        List<String> strList = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {
            for (int j = i + 1; j < list.size(); j++) {
                if (son == 2) {
                    strList.add(list.get(i) + "," + list.get(j));
                } else {
                    for (int k = j + 1; k < list.size(); k++) {
                        if (son == 3) {
                            strList.add(list.get(i) + "," + list.get(j) + "," + list.get(k));
                        } else {
                            for (int m = k + 1; m < list.size(); m++) {
                                strList.add(list.get(i) + "," + list.get(j) + "," + list.get(k) + "," + list.get(m));
                            }
                        }
                    }
                }
            }
        }
        return strList;
    }

    private void updateIndexMap(List<TempData> indexMapList, List<Integer> sonListStr,
                                Map<String, TempData> continueDataMaps,
                                int row, List<Integer>[] lists, int col,
                                Set<String> trueIndexCol, List<TempData> dataTrues,
                                Map<Integer, List<TempData>> tempDataTruesMap, List<TempData> continueRemoveDataMaps) throws CloneNotSupportedException {
        for (TempData dataMap : indexMapList) {
            if (dataMap.getFlag()) {
                dataMap.setCount(0);
                dataMap.setFlag(false);
            }

            List<String> list1 = new ArrayList<>(Arrays.asList(dataMap.getIndex().split(",")));
            List<String> list2 = new ArrayList<>();
            for (Integer integer : sonListStr) {
                list2.add(integer + "");
            }
            if (list1.containsAll(list2) && !dataMap.getFlag()) {
                dataMap.setCount(dataMap.getCount() + 1);
                dataMap.setFlag(true);
            } else {
                dataMap.setCount(dataMap.getCount() + 1);
            }
            if (trueIndexCol.contains(dataMap.getIndex() + "=" + dataMap.getCol())) {
                TempData clone = (TempData) dataMap.clone();
                clone.setWinRow(row);
                if (dataMap.getFlag()) {
                    clone.setSedWin(true);
                    trueIndexCol.remove(dataMap.getIndex() + "=" + dataMap.getCol());
                }
                setRealFirstCode(lists, col, clone);
                dataTrues.add(clone);

                if (tempDataTruesMap.containsKey(row + 1)) {
                    tempDataTruesMap.get(row + 1).add(clone);
                } else {
                    List<TempData> list = new ArrayList<>();
                    list.add(clone);
                    tempDataTruesMap.put(row + 1, list);
                }

            }

            if (continueDataMaps.containsKey(dataMap.getIndex() + "-" + dataMap.getCol()) && continueDataMaps.get(dataMap.getIndex() + "-" + dataMap.getCol()).getSerWin()) {
                if (!sonListStr.contains(dataMap.getIndex())) {
                    continueDataMaps.get(dataMap.getIndex() + "-" + dataMap.getCol()).setSerCount(continueDataMaps.get(dataMap.getIndex() + "-" + dataMap.getCol()).getSerCount() + 1);
                } else {
                    continueDataMaps.get(dataMap.getIndex() + "-" + dataMap.getCol()).setSerWin(false);
                }
            } else {
                //第一次中奖记录
                if (dataMap.getFlag()) {
                    dataMap.setSerCount(1);
                    dataMap.setSerWin(true);
                    //重复中奖数据
                    if (continueDataMaps.containsKey(dataMap.getIndex() + "-" + dataMap.getCol())) {
                        TempData remove = continueDataMaps.remove(dataMap.getIndex() + "-" + dataMap.getCol());
                        dataMap.setSerWinVersion(remove.getSerWinVersion() + 1);
                        continueRemoveDataMaps.add(remove);
                    }
                    continueDataMaps.put(dataMap.getIndex() + "-" + dataMap.getCol(), dataMap);
                }
            }
        }
    }

    private List<String> getLastGuessCode(List<Integer>[][] arr, int row, List<List<String>> resultList) {
        List<String> lastList = resultList.get(resultList.size() - 1);
        List<String> realLastList = new ArrayList<>();
        realLastList.add(0, 1 + Integer.parseInt(lastList.get(0)) + "");
        int page = 1;
        for (int i = 0; i < lastList.size() / 5; i++) {
            List<String> list = lastList.subList(page, page + 5);
            page = page + 5;
            if ("false".equals(list.get(4))) {
                realLastList.add(list.get(0));
                realLastList.add(1 + Integer.parseInt(list.get(1)) + "");
                String index = list.get(0);
                String[] split = index.split(",");
                StringBuffer sb = new StringBuffer();
                int cell = Integer.parseInt(list.get(3)) - 1;
                for (int j = 0; j < split.length; j++) {
                    sb.append(arr[row][cell].get(Integer.parseInt(split[j]) - 1));
                    if (j < split.length - 1) {
                        sb.append(",");
                    }
                }
                List<String> listSrt = new ArrayList<>(Arrays.asList(split));
                while (cell > 0) {
                    List<String> list0 = new ArrayList<>();
                    for (int j = 0; j < listSrt.size(); j++) {
                        list0.add("" + arr[row][cell].get(Integer.parseInt(listSrt.get(j)) - 1));
                    }
                    listSrt.clear();
                    listSrt.addAll(list0);
                    cell--;
                }
                StringBuffer sb2 = new StringBuffer();
                for (int j = 0; j < listSrt.size(); j++) {
                    sb2.append(arr[row][cell].get(Integer.parseInt(listSrt.get(j)) - 1));
                    if (j < split.length - 1) {
                        sb2.append(",");
                    }
                }
                realLastList.add(sb2.toString());
                realLastList.add(list.get(3));
                realLastList.add(" ");
            }
        }
        return realLastList;
    }


    private void setRealFirstCode(List<Integer>[] lists, int col, TempData dataMap) {
        String index = dataMap.getIndex();

        String[] split = index.split(",");
        StringBuffer sb = new StringBuffer();
        for (int j = 0; j < split.length; j++) {
            sb.append(lists[col].get(Integer.parseInt(split[j]) - 1));
            if (j < split.length - 1) {
                sb.append(",");
            }
        }

        List<String> listSrt = new ArrayList<>(Arrays.asList(split));
        int cell = col;
        while (cell > 0) {
            List<String> list = new ArrayList<>();
            for (int j = 0; j < listSrt.size(); j++) {
                try {
                    list.add("" + lists[cell].get(Integer.parseInt(listSrt.get(j)) - 1));
                } catch (NumberFormatException e) {
                    e.printStackTrace();
                }
            }
            listSrt.clear();
            listSrt.addAll(list);
            cell--;
        }
        StringBuffer sb2 = new StringBuffer();
        for (int j = 0; j < listSrt.size(); j++) {
            sb2.append(lists[cell].get(Integer.parseInt(listSrt.get(j)) - 1));
            if (j < split.length - 1) {
                sb2.append(",");
            }
        }
        dataMap.setRealFirstCode(sb2.toString());
    }


    private void readResultLists(List<List<String>> resultLists) {
        resultLists.addAll(ReadExcelUtil.readExcelResult("超过结果", 2));
    }
}
